# frozen_string_literal: true

require "spec_helper"

RSpec.describe "User sees Vulnerability report", :js, feature_category: :vulnerability_management do
  let_it_be(:user) { create(:user) }
  let_it_be(:project) { create(:project, :repository) }
  let_it_be(:pipeline) { create(:ee_ci_pipeline, project: project) }
  let_it_be(:ci_build) { create(:ci_build, :sast, pipeline: pipeline, status: "success") }

  let_it_be(:sast_vulnerability) do
    create(:vulnerability, :sast, title: "SAST vulnerability", project: project)
  end

  let_it_be(:sast_vulnerabilities_scanner) do
    create(
      :vulnerabilities_scanner,
      name: 'SAST Scanner',
      vendor: 'GitLab',
      project: project
    )
  end

  let_it_be(:sast_vulnerabilities_finding) do
    create(
      :vulnerabilities_finding,
      :identifier,
      vulnerability: sast_vulnerability,
      report_type: :sast,
      scanner: sast_vulnerabilities_scanner,
      project: project
    )
  end

  let_it_be(:dast_vulnerability) do
    create(:vulnerability, :dast, title: "DAST vulnerability", project: project)
  end

  let_it_be(:dast_vulnerabilities_scanner) do
    create(
      :vulnerabilities_scanner,
      name: 'DAST Scanner',
      vendor: 'GitLab',
      project: project
    )
  end

  let_it_be(:dast_vulnerabilities_finding) do
    create(
      :vulnerabilities_finding,
      :identifier,
      vulnerability: dast_vulnerability,
      report_type: :dast,
      scanner: dast_vulnerabilities_scanner,
      project: project
    )
  end

  before do
    stub_licensed_features(
      security_dashboard: true,
      sast: true
    )
    project.add_developer(user)
    sign_in(user)
  end

  it "shows the Vulnerability report" do
    visit(project_security_vulnerability_report_index_path(project))

    expect(page).to have_content "Vulnerability report"

    expect(page).to have_content sast_vulnerability.title
    expect(page).to have_content dast_vulnerability.title

    # This click opens the filter
    click_on 'All tools'

    find('[data-testid="listbox-item-GitLab.SAST"]').click

    expect(page).to have_content sast_vulnerability.title
    expect(page).to have_no_content dast_vulnerability.title

    # The filter stays open, so it doesn't need to be opened again
    find('[data-testid="listbox-item-GitLab.DAST"]').click
    # Clicking an item in the filter toggles it, so this deselects 'SAST'
    find('[data-testid="listbox-item-GitLab.SAST"]').click

    expect(page).to have_no_content sast_vulnerability.title
    expect(page).to have_content dast_vulnerability.title
  end

  context "when a scanner has produced more than one type of finding" do
    let_it_be(:secret_detection_vulnerability) do
      create(:vulnerability, :secret_detection, title: "Secret Detection vulnerability", project: project)
    end

    # Note the scanner for this is the same as for the
    # sast_vulnerabilities_finding.  So once this finding is created
    # sast_scanner will have produced 2 different types of finding,
    # :sast and :secret_detection
    let_it_be(:secret_detection_vulnerabilities_finding) do
      create(
        :vulnerabilities_finding,
        :identifier,
        vulnerability: secret_detection_vulnerability,
        report_type: :secret_detection,
        scanner: sast_vulnerabilities_scanner,
        project: project
      )
    end

    it "shows the Vulnerability report", :aggregate_failures do
      visit(project_security_vulnerability_report_index_path(project))
      expect(page).to have_content "Vulnerability report"

      expect(page).to have_content sast_vulnerability.title
      expect(page).to have_content dast_vulnerability.title
      expect(page).to have_content secret_detection_vulnerability.title

      click_on 'All tools'

      find('[data-testid="listbox-item-GitLab.SAST"]').click
      expect(page).to have_content sast_vulnerability.title
      expect(page).to have_no_content dast_vulnerability.title
      expect(page).to have_no_content secret_detection_vulnerability.title

      find('[data-testid="listbox-item-GitLab.SECRET_DETECTION"]').click
      find('[data-testid="listbox-item-GitLab.SAST"]').click # Deselects SAST from the filter
      expect(page).to have_no_content sast_vulnerability.title
      expect(page).to have_no_content dast_vulnerability.title
      expect(page).to have_content secret_detection_vulnerability.title
    end
  end

  context "when dismissing a vulnerability" do
    let_it_be(:vulnerabilities) { create_list(:vulnerability, 5, :with_findings, project: project) }

    it "dismisses the vulnerability" do
      visit project_security_vulnerability_report_index_path(project)
      wait_for_all_requests

      vulnerabilities.each do |vulnerability|
        expect(page).to have_content(vulnerability.title)
      end

      change_all(state: :dismissed, reason: :used_in_tests, comment: "A comment")

      vulnerabilities.each do |vulnerability|
        expect(page).to have_no_content(vulnerability.title)
      end

      filter_by(status: :dismissed)

      vulnerabilities.each do |vulnerability|
        expect(page).to have_content(vulnerability.title)
      end
    end
  end

  def filter_by(status:)
    click_on "Needs triage +1 more"
    find("li[data-testid='listbox-item-#{status.to_s.upcase}']").click
    find("h2[data-testid='vulnerability-report-header']").click
    wait_for_all_requests
  end

  def change_all(state:, reason:, comment:)
    find('input[data-testid="vulnerability-checkbox-all"]').check
    click_on 'Set status'

    find("li[data-testid='listbox-item-#{state}']").click
    find("div[data-testid='dismissal-reason-listbox']").click
    find("li[data-testid='listbox-item-#{reason}']").click
    find("[data-testid='change-status-comment-textbox']").fill_in(with: comment)
    click_button 'Change status'
    wait_for_all_requests
  end
end
